package com.tim.helper.string;

import com.tim.MainHelper;
import com.tim.util.StringAnalysisUtil;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 按行分割；逐个处理：生成后手动调整，或二次加工
 * 	header
 * 		包声明。引入必要的依赖
 * 		注释。提取注释内容，原样返回
 * 		类注解。原样返回
 * 		类声明。转换为对应类声明，无注解时增加注解
 * 	方法信息
 * 		方法注解。原样返回
 * 		方法签名。转换为方法实现，添加注解
 * 		注释。提取注释内容，原样返回
 * 		其他。原样返回
 *
 */
public class CodeGen {

	public String content = "@CMD(description = \"事件触达列表\")\r\n" +
			"    Pager<MisEventTriggerResp> getEventTriggerByPage(MisListEventTriggerReq req);\r\n" +
			"\r\n" + 
			"\r\n" + 
			"    @CMD(description = \"新建事件触达配置\")\r\n" + 
			"    void addEventTrigger(AddEventTriggerReq req);\r\n" + 
			"\r\n" + 
			"    @CMD(description = \"事件触达详情\")\r\n" + 
			"    MisEventTriggerDetailResp getEventTriggerDetail(IdReq req);\r\n" + 
			"\r\n" + 
			"    @CMD(description = \"修改事件触达配置\")\r\n" + 
			"    Integer updateEventTrigger(MisUpdateEventTriggerReq req);\r\n" + 
			"\r\n" + 
			"    @CMD(description = \"开关事件触达配置\")\r\n" + 
			"    Integer switchEventTrigger(MisSwitchEventTriggerReq req);";

	@Test
	public void printService(){
		String code = "";
		content = StringUtils.isNotBlank(code)?code:content;
		doPrintService(content, MainHelper.Type.T0);
	}
	@Test
	public void printManager(){
		String code = "";
		content = StringUtils.isNotBlank(code)?code:content;
		doPrintManager(content, MainHelper.Type.T0);
	}
	@Test
	public void printSwagger(){
		String code = "";
		content = StringUtils.isNotBlank(code)?code:content;
		doPrintSwagger(content, "", MainHelper.Type.T0);
	}

	/**
	 * service接口模板，替换：INTERFACE_NAME，TABLE_NAME，TABLE_DESC
	 */
	public interface ServiceTemplate {
		String getTemplate() throws Exception;

		static String getTemplate(int type){
			// 0每日说 1懒猪 2山海平店绩
			return type==MainHelper.Type.T0 ? new DailyImpl().getTemplate()
					: type==MainHelper.Type.T1 ? new LazyPigImpl().getTemplate()
					: type==MainHelper.Type.T2 ? new ShpMallImpl().getTemplate()
					: type==MainHelper.Type.T3 ? new FbankImpl().getTemplate()
					: "";
		}

		class LazyPigImpl implements ServiceTemplate {
			public String getTemplate(){
				String template = "com.xqxc.pigear.bean.common.request.IdReq;\n" +
						"import com.xqxc.pigear.bean.common.Pager;\n" +
						"import com.xqxc.rpc.anno.Api;\n" +
						"import com.xqxc.rpc.anno.CMD;\n" +
						"\n" +
						"/**\n" +
						" * @describe TABLE_DESC\n" +
						" * @author:Tim\n" +
						" * @date: " + new SimpleDateFormat("yyyy-MM-dd").format(new Date())+"\n"+
						" */\n" +
						"@Api\n" +
						"public interface INTERFACE_NAMEService {\n" +
						"\n" +
						"    @CMD(cmd = \"insertTABLE_NAME\", description = \"新增TABLE_DESC\")\n" +
						"    int add(AddTABLE_NAMEReq req);\n" +
						"\n" +
						"    @CMD(cmd = \"deleteByPrimaryKey\", description = \"删除TABLE_DESC\")\n" +
						"    int delete(IdReq req);\n" +
						"\n" +
						"    @CMD(cmd = \"updateTABLE_NAME\", description = \"更新TABLE_DESC\")\n" +
						"    int update(UpdateTABLE_NAMEReq req);\n" +
						"\n" +
						"    @CMD(cmd = \"listTABLE_NAME\", description = \"获取TABLE_DESC列表\")\n" +
						"    Pager<ListTABLE_NAMEResp> list(ListTABLE_NAMEReq req);\n" +
						"\n" +
						"    @CMD(cmd = \"selectByPrimaryKey\", description = \"获取TABLE_DESC详情\")\n" +
						"    DetailTABLE_NAMEResp detail(IdReq req);\n" +
						"\n" +
						"}";
				return template;
			}
		}

		class DailyImpl implements ServiceTemplate {
			public String getTemplate(){
				String template = "import com.xqxc.biz.bean.Pager;\n" +
						"import com.xqxc.plat.anno.Api;\n" +
						"\n" +
						"/**\n" +
						" * @describe TABLE_DESC\n" +
						" * @author:Tim\n" +
						" * @date: " + new SimpleDateFormat("yyyy-MM-dd").format(new Date())+"\n"+
						" */\n" +
						"@Api\n" +
						"public interface INTERFACE_NAMEService {\n" +
						"\n" +
						"    /**新增TABLE_DESC*/\n" +
						"    int add(AddTABLE_NAMEReq req);\n" +
						"\n" +
						"    /**删除TABLE_DESC*/\n" +
						"    int delete(IdRequest req);\n" +
						"\n" +
						"    /**更新TABLE_DESC*/\n" +
						"    int update(UpdateTABLE_NAMEReq req);\n" +
						"\n" +
						"    /**获取TABLE_DESC列表*/\n" +
						"    Pager<ListTABLE_NAMEResp> list(ListTABLE_NAMEReq req);\n" +
						"\n" +
						"    /**获取TABLE_DESC详情*/\n" +
						"    DetailTABLE_NAMEResp detail(IdReq req);\n" +
						"\n" +
						"}";
				return template;
			}
		}

		class ShpMallImpl implements ServiceTemplate {
			public String getTemplate(){
				String template = "import import com.shp.tsfservice.sic.component.dto.PageResponse;\n" +
						"import com.shp.tsfservice.pharmacy.mall.client.model.IdReq;\n" +
						"\n" +
						"\n" +
						"/**\n" +
						" * @author:Tim\n" +
						" * @date: " + new SimpleDateFormat("yyyy-MM-dd").format(new Date())+"\n"+
						" * @description: TABLE_DESC\n" +
						" */\n" +
						"public interface INTERFACE_NAMEService {\n" +
						"\n" +
						"    /**\n" +
						"     * 添加TABLE_DESC\n" +
						"     */\n" +
						"    void add(AddTABLE_NAMEReq req);\n" +
						"\n" +
						"    /**\n" +
						"     * 删除TABLE_DESC\n" +
						"     */\n" +
						"    void delete(DelTABLE_NAMEReq req);\n" +
						"\n" +
						"    /**\n" +
						"     * 修改TABLE_DESC\n" +
						"     */\n" +
						"    void update(UpdTABLE_NAMEReq req);\n" +
						"\n" +
						"    /**\n" +
						"     * TABLE_DESC列表\n" +
						"     */\n" +
						"    PageResponse<TABLE_NAMEListResp> list(TABLE_NAMEListReq req);\n" +
						"\n" +
						"    /**\n" +
						"     * TABLE_DESC详情\n" +
						"     */\n" +
						"    TABLE_NAMEDetailResp detail(IdReq req);\n" +
						"\n" +
						"}";
				return template;
			}
		}

		class FbankImpl implements ServiceTemplate {
			public String getTemplate(){
				String template = "";
				return template;
			}
		}


	}

	public List<String> doPrintService(String code, int type){
		List<String> implList = Printer.getImpl(type).getContent(code, type);
		implList.forEach(System.out::println);
		return implList;
	}

	public List<String> doPrintManager(String code, int type){
		List<String> managerList = Printer.getManager(type).getContent(code, type);
		managerList.forEach(System.out::println);
		return managerList;
	}

	public List<String> doPrintSwagger(String code, String pathAppend, int type){
		List<String> swaggerList = Printer.getSwagger(type, pathAppend).getContent(code, type);
		swaggerList.forEach(System.out::println);
		return swaggerList;
	}

	public interface Printer {
		String serviceVar = "service";
		String managerVar = "manager";
		String mapperVar = "mapper";
		String INTERFACE_FLAG = " interface ";// 接口标志字符串
		String METHOD_SPLITOR = "[\r\n]+";// 方法分隔符

		List<String> getContent(String code, int type);

		/****************按类型获取实现******************/
		static Printer getImpl(int type){
			Printer printer = type==MainHelper.Type.T0 ? new ServiceImplPrinter()
					: new ServiceImplPrinter();
			return printer;
		}

		static Printer getManager(int type){
			Printer printer = type==MainHelper.Type.T0 ? new ManagerPrinter()
					: new ManagerPrinter();
			return printer;
		}

		static Printer getSwagger(int type, String pathAppend){
			Printer printer = type==MainHelper.Type.T0 ? new SwaggerPrinter(pathAppend)
					: new SwaggerPrinter(pathAppend);
			return printer;
		}

		/****************获取类名，一般不改******************/

		static String getInterfaceName(String info) {
			String interfaceName = info.substring(info.indexOf(Printer.INTERFACE_FLAG))
					.trim().split("\\s+")[1];
			return interfaceName;
		}

		static String getImplName(String interfaceName){
			return interfaceName.trim().replaceAll("Service$", "ServiceImpl");
		}

		static String getManagerName(String interfaceName){
			return interfaceName.trim().replaceAll("Service$", "Manager");
		}

		static String getMapperName(String interfaceName){
			return interfaceName.trim().replaceAll("Service$", "DOMapper");
		}

		static String getControllerName(String interfaceName){
			return interfaceName.trim().replaceAll("Service$", "Controller");
		}
	}

	public static abstract class AbstractPrinter implements Printer{
		StringBuffer commentBuf = new StringBuffer();// 注释缓存
		String varName = null;
		boolean printComment = true;
		boolean printAnno = true;
		int type = MainHelper.Type.T0;
		/**
		 */
		public List<String> getContent(String code, int type) {
			this.type = type;

			// 移除首尾空白；按METHOD_SPLITOR分隔为数组
			boolean isHeader = code.contains(INTERFACE_FLAG);
			String[] strs = code.trim().split(METHOD_SPLITOR);
			List<String> contentList = new ArrayList<>();
			for (int i = 0; i < strs.length; i++) {
				String str = strs[i];
				if(isHeader){
					// 处理包声明、引用
					str = str.trim();
					List<String> list = handleHeader(str);
					contentList.addAll(list);
					isHeader = !str.contains(INTERFACE_FLAG);
				}else{
					String methodContent = handleMethodContent(str.trim());
					contentList.add(methodContent);
				}
			}

			return postHandle(contentList);
		}

		/**
		 * 处理header；
		 * 		包声明。引入必要的依赖
		 * 		注释。提取注释内容，原样返回
		 * 		类注解。增加、转换注解
		 * 		类声明。转换为对应类声明
		 * 		方法信息。调用方法处理
		 * 		其他。直接返回
		 */
		public List<String> handleHeader(String header) {
			String[] lines = header.split("\n");
			List<String> list = new ArrayList<>();
			for(String line : lines){
				String trim = line.trim();
				if(trim.startsWith("package")){
					// 包行
					line = handlePackageLine(line);
				}
				else if(isComment(line)){
					// 注释行
					if(isCommentStart(line)){
						commentBuf = new StringBuffer();
					}
					commentBuf.append(getComment(line));
					line = handleCommentLine(line);
				}
				else if(trim.startsWith("@")){
					// 标记注解行
					line = handleAnnotationLine(line);
				}
				else if(trim.contains(Printer.INTERFACE_FLAG)){
					// 接口行
					line = handleInterfaceLine(line);
				}
				else{
					// 其他情况；如空行、import等
					line = handleCommonLine(line);
				}
				list.add(line);
			}
			return list;
		}

		/**
		 * 方法信息
		 * 		方法注解。提取注解内容，添加对应注解
		 * 		方法签名。转换为方法实现
		 * 		注释。提取注释内容，原样返回
		 * 		其他。直接返回
		 */
		public String handleMethodContent(String info) {
			String[] lines = info.split("\n");
			StringBuilder builder = new StringBuilder();
			for(int i=0; i<lines.length; i++){
				String line = lines[i];
				if(StringUtils.isBlank(line)||line.contains("@")){
					// 注解行
					line = handleAnnotationLine(line);
				}else if(notMethodSignature(line)){
					if(isComment(line)){
						// 注释行
						if(isCommentStart(line)){
							commentBuf = new StringBuffer();
						}
						commentBuf.append(getComment(line));
						line = handleCommentLine(line);
					}else{
						// 非方法签名行；如空行
						line = handleCommonLine(line);
					}
				}else{
					System.out.println(line);
					// 方法签名行
					line = handleMethodSignatureLine(line);
				}
				builder.append(line);
			}
			return builder.toString();
		}

		public String handlePackageLine(String line){
			return line;
		}

		public boolean isComment(String line) {
			line = line.trim();
			return line.startsWith("/*")
					|| line.startsWith("//")
					|| line.startsWith("*")
					|| line.endsWith("*/");
		}

		public boolean isCommentStart(String line) {
			line = line.trim();
			return line.startsWith("/*");
		}

		public String getComment(String line) {
			String comment = line.trim()
					.replaceAll("\\s+", " ")
					.replaceAll("(\\*/)$", "")
					.replaceAll("^((/\\*+)|(//)|(\\*))", "");
			return comment.trim().startsWith("@") ? "" : comment;
		}

		public String handleCommonLine(String line){
			// import、空行等
			return line+"\n";
		}

		public String handleCommentLine(String line){
			// 注释行
			return printComment ? line+"\n" : "";
		}

		public String handleAnnotationLine(String line){
			// 注解行
			return printAnno ? line+"\n" : "";
		}

		public String handleInterfaceLine(String line){

			return line+"\n";
		}

		public boolean notMethodSignature(String line) {
			line = line.trim().replaceAll("\\s+", " ");
			return line.length()<10
					|| line.startsWith("*")
					|| line.startsWith("/")
					|| line.startsWith("@");
		}

		public String handleMethodSignatureLine(String line){
			// 方法签名行
			StringBuilder builder = new StringBuilder();
			// 拼接方法调用
			String temp = line.trim()
					.replaceAll("\\s+", " ")
					.replaceAll("^public\\s", " ");
			builder.append("public "+temp.replaceAll(";", "{\n"));

			if(line.contains(" void ") || line.startsWith("void ")){
				builder.append("\t");
			}else{
				builder.append("\treturn ");
			}
			builder.append(getMethodCallLine(temp))
					.append("\n}\n");
			return builder.toString();
		}

		public String getMethodCallLine(String methodLine){
			StringBuilder builder = new StringBuilder(varName).append(".");
			int loc = methodLine.indexOf('(');
			// 空格分隔，最后一个为方法名
			String preStr = methodLine.substring(0, loc).trim();
			String[] preStrs = preStr.split(" ");
			String methodName = preStrs[preStrs.length-1];
			builder.append(methodName);
			// 逗号分隔再空格分隔，最后一个为参数名
			String sufStr = methodLine.substring(loc+1, methodLine.indexOf(')'));
			String[] sufStrs = sufStr.trim().split(",");
			builder.append("(");
			for(int i=0; i<sufStrs.length; i++){
				String str = sufStrs[i].trim();
				String[] strs = str.split(" ");
				String argName = strs[strs.length-1];
				builder.append(i==0?"":", ").append(argName);
			}
			builder.append(");");
			return builder.toString();
		}

		/**按type后置处理代码*/
		public List<String> postHandle(List<String> list){
			String content = list.stream()
					.collect(Collectors.joining("\n"));
			content = content.replaceAll(METHOD_SPLITOR, "\n")
					.replaceAll("value\\s*=\\s*\"\\s*", "value=\"")
					.replaceAll("tags\\s*=\\s*\"\\s*", "value=\"")
					.replaceAll("}", "}\n");

			return Arrays.stream(content.split("\n"))
					.collect(Collectors.toList());
		}

	}

	static class ServiceImplPrinter extends AbstractPrinter{
		{
			varName = managerVar;
		}

		public String handlePackageLine(String line){
			// 引入的依赖
			String appendInfo = "\nimport lombok.extern.slf4j.Slf4j;\n"
					+ "import com.alibaba.dubbo.config.annotation.Service;\n"
					+ "import javax.annotation.Resource;";
			if(type==MainHelper.Type.T0){
				appendInfo += "";
			}
			line = line+"\n"+appendInfo;
			return line;
		}

		public String handleInterfaceLine(String line){
			String interfaceName = Printer.getInterfaceName(line);
			String implName = Printer.getImplName(interfaceName);
			String managerName = Printer.getManagerName(interfaceName);

			// 前置注解，后置变量
			String preAnno = "@Component";
			String sufVar = String.format("@Resource\nprivate %s %s;",
					managerName, managerVar);
			if(type==MainHelper.Type.T0){
				sufVar += "";
			}
			line = String.format("%s\npublic class %s implements %s {\n%s\n",
					preAnno, implName, interfaceName, sufVar);
			return line;
		}

		public String handleMethodSignatureLine(String line){
			return "@Override\n"+super.handleMethodSignatureLine(line);
		}
	}

	static class ManagerPrinter extends AbstractPrinter{
		{
			varName = mapperVar;
		}

		public String handlePackageLine(String line){
			String appendInfo = "\nimport lombok.extern.slf4j.Slf4j;\n" +
					"import org.springframework.stereotype.Component;\n" +
					"import javax.annotation.Resource;";
			if(type==MainHelper.Type.T0){
				appendInfo += "";
			}
			line = line+"\n"+appendInfo;
			return line;
		}

		public String handleInterfaceLine(String line){
			String interfaceName = Printer.getInterfaceName(line);
			String managerName = Printer.getManagerName(interfaceName);
			String mapperName = Printer.getMapperName(interfaceName);

			// 前置注解，后置变量
			String preAnno = "@Component";
			String sufVar = String.format("@Resource\nprivate %s %s;",
					mapperName, mapperVar);
			if(type==MainHelper.Type.T0){
				sufVar += "";
			}
			line = String.format("%s\npublic class %s {\n%s\n",
					preAnno, managerName, sufVar);

			return line;
		}

	}

	static class SwaggerPrinter extends AbstractPrinter{
		{
			varName = serviceVar;
		}
		String template = "\r\n" +
				"    @ApiOperation(value = \"ANNOVAL\", notes = \"ANNOVAL\")\r\n" +
				"    @PostMapping(\"cmd=INTERFACE_FULL_NAME.METHODNAME\")\r\n" +
				"    METHODINFO";
		String pathAppend="";
		public SwaggerPrinter(String pathAppend) {
			if(StringUtils.isNotBlank(pathAppend)){
				this.pathAppend = pathAppend;
			}
		}

		public String handlePackageLine(String line){
			String appendInfo = "\nimport io.swagger.annotations.Api;\n"
					+ "import io.swagger.annotations.ApiOperation;\n"
					+ "import org.springframework.web.bind.annotation.PostMapping;\n"
					+ "import org.springframework.web.bind.annotation.RequestBody;\n"
					+ "import org.springframework.web.bind.annotation.RequestMapping;\n"
					+ "import org.springframework.web.bind.annotation.RestController;";
			if(type==MainHelper.Type.T0){
				appendInfo += "";
			}
			line = line+"\n"+appendInfo;
			return line;
		}

		public String handleInterfaceLine(String line){
			String interfaceName = Printer.getInterfaceName(line);


			String implName = Printer.getImplName(interfaceName);
			String controllerName = Printer.getControllerName(interfaceName);

			// 前置注解，后置变量
			String preAnno = String.format("@Api(value = \"%1$s\",tags = \"%1$s\")\n" +
							"@Slf4j\n@RestController\n@RequestMapping(\"\")\n",
					commentBuf.toString());
			if(type==MainHelper.Type.T0){
				preAnno += "";
			}
			String sufVar = String.format("@Resource\nprivate %s %s;",
					implName, serviceVar);
			if(type==MainHelper.Type.T0){
				sufVar += "";
			}
			line = String.format("%s\npublic class %s {\n%s\n",
					preAnno, controllerName, sufVar);

			return line;
		}

		public String handleMethodSignatureLine(String line){
			// 方法签名行
			String[] methodInfo = StringAnalysisUtil.getMethodInfo(line);

			String preAnno = String.format("@ApiOperation(tags=\"%s\")\n" +
							"@PostMapping(\"/%s\")\n",
					commentBuf.toString(), methodInfo[1]+pathAppend);
			commentBuf = new StringBuffer();
			String methodContent = super.handleMethodSignatureLine(line)
					.replaceFirst("\\(", "(@RequestBody @Valid ");
			return preAnno+methodContent;
		}

	}
}
